#include "union_find.h"
#include <queue>
#include <vector>
using std::vector; 

#include <functional>
#include <iostream>
using std::cout;
using std::cin;
using std::endl;

#include <algorithm>

void test_union_find();

struct edge
{
    int m_vertex1_num;
    int m_vertex2_num;
    int m_weight;

    edge(int vertex1_num = 0, int vertex2_num = 0, int weight = 0)
        : m_vertex1_num(vertex1_num)
        , m_vertex2_num(vertex2_num)
        , m_weight(weight)
    {

    }

    bool operator==(const edge& x) const
    {
        return m_weight == x.m_weight;
    }
    bool operator!=(const edge& x) const
    {
        return !(*this == x);
    }
    bool operator<(const edge& x) const
    {
        return m_weight < x.m_weight;
    }
    bool operator<=(const edge& x) const
    {
        return *this < x || *this == x;
    }
    bool operator>(const edge& x) const
    {
        return !(*this <= x);
    }
    bool operator>=(const edge& x) const
    {
        return !(*this < x);
    }
};

// void Kruskal(int vertex_quantity)
// {

// }

/*
    Kruskal
    假设边的权重 >= 0
*/
void solution()
{
    int n = 0; // 顶点数
    int e = 0; // 边数
    cin >> n >> e;
    
    std::priority_queue<edge, std::vector<edge>, std::greater<edge>> min_heap;
    int vertex1 = 0;
    int vertex2 = 0;
    int weight = 0;
    for (int i = 0; i < e; ++i)
    {
        cin >> vertex1 >> vertex2 >> weight;
        min_heap.push({vertex1, vertex2, weight});
    }

    union_find vertex(n);
    edge cur;
    int break_point = 0;
    long long weight_sum = 0;  // 最后一个错误原因 long long
    // 2.0版本: !min_heap.empty()
    // 3.0版本: e > 0 && break_point < n - 1
    while (!min_heap.empty()) // 改一下这个能过测试点2和3 原始1.0版本: while (1) 因为存在不连通的图或者是只有1个顶点,0条边
    {
        cur = min_heap.top();
        min_heap.pop();
        int group_sign1 = vertex.find(cur.m_vertex1_num);
        int group_sign2 = vertex.find(cur.m_vertex2_num);
        // if (group_sign1 != group_sign2)
        // {
        //     vertex.unite(group_sign1, group_sign2);
        //     ++break_point;
        //     weight_sum += cur.m_weight;
        // }
        if (group_sign1 == group_sign2)
        {
            continue;
        }
        else
        {
            vertex.unite(group_sign1, group_sign2);
            ++break_point;
            weight_sum += cur.m_weight;
        }

        if (break_point == n - 1)
        {
            break;
        } 
    }


    //cout << weight_sum << endl;
    if (break_point == n - 1)
    {
        cout << weight_sum << endl;
    }
    else 
    {
        // 如果不存在最小生成树, 不是这里的问题
        cout << 0 << endl;
    }
}

void solution2()
{
    int n = 0; // 顶点数
    int e = 0; // 边数
    cin >> n >> e;
    //edge* edge_set = new edge[e];

    vector<edge> edge_set(e);
    int vertex1 = 0;
    int vertex2 = 0;
    int weight = 0;
    for (int i = 0; i < e; ++i)
    {
        cin >> vertex1 >> vertex2 >> weight;
        edge_set[i].m_vertex1_num = vertex1;
        edge_set[i].m_vertex2_num = vertex2;
        edge_set[i].m_weight = weight;
    }

    std::sort(edge_set.begin(), edge_set.end()); // 默认是升序

    union_find vertex(n);
    int break_point = 0;
    int weight_sum = 0;
    for (int i = 0; i < e; ++i)
    {
        //edge_set[i];
        int group_sign1 = vertex.find(edge_set[i].m_vertex1_num);
        int group_sign2 = vertex.find(edge_set[i].m_vertex2_num);
        if (group_sign1 == group_sign2)
        {
            continue;
        }
        else
        {
            vertex.unite(group_sign1, group_sign2);
            ++break_point;
            weight_sum += edge_set[i].m_weight;
        }

        if (break_point == n - 1)
        {
            break;
        } 
    }

    cout << weight_sum << endl;
}

int main()
{
    solution();
    //test_union_find();
    return 0;
}

void test_union_find()
{
    union_find uf(5);
    cout << uf.find(5) << endl;
    uf.unite(uf.find(5), uf.find(1));
    uf.unite(uf.find(2), uf.find(4));
    uf.unite(uf.find(3), uf.find(4));
}

